// Learn TypeScript:
//  - https://docs.cocos.com/creator/2.4/manual/en/scripting/typescript.html
// Learn Attribute:
//  - https://docs.cocos.com/creator/2.4/manual/en/scripting/reference/attributes.html
// Learn life-cycle callbacks:
//  - https://docs.cocos.com/creator/2.4/manual/en/scripting/life-cycle-callbacks.html

import { Input, KeyCode } from "../gameModule/Framework/InputManager";
import { IState, StateMachine } from "../gameModule/Framework/StateMachine";

const {ccclass, property} = cc._decorator;

class Idle implements IState{
    Name: string = "Idle";

    private m_skin = null
    constructor(mainNode:cc.Node) {
        this.m_skin = mainNode.getChildByName('skin');
        
    }

    OnEnter(): void{
        this.m_skin.getComponent(cc.Animation).play('idle');
    };
    Tick(): void{

    };
    OnExit(): void{

    };
}

class Run implements IState{
    Name: string = "Run";

    private m_skin = null
    constructor(mainNode:cc.Node) {
        this.m_skin = mainNode.getChildByName('skin');
        
    }

    OnEnter(): void{
        this.m_skin.getComponent(cc.Animation).play('run');
    };
    Tick(): void{

    };
    OnExit(): void{

    };
}

class Attack implements IState{
    Name: string = "Attack";

    private mainNode:cc.Node = null
    private m_skin = null
    constructor(mainNode:cc.Node) {
        this.mainNode = mainNode;
        this.m_skin = mainNode.getChildByName('skin');
    }

    OnEnter(): void{
        this.m_skin.getComponent(cc.Animation).play('attack');
        // 添加动画结束监听
        this.m_skin.getComponent(cc.Animation).once(cc.Animation.EventType.FINISHED, () => {
            this.mainNode.getComponent(Player).isAttack = false;
        });
    };
    Tick(): void{

    };
    OnExit(): void{

    };
}

class Jump implements IState{
    Name: string = "Jump";

    private m_skin = null
    constructor(mainNode:cc.Node) {
        this.m_skin = mainNode.getChildByName('skin');
    }

    OnEnter(): void{
        this.m_skin.getComponent(cc.Animation).play('jump-in');
        this.m_skin.getComponent(cc.Animation).once(cc.Animation.EventType.FINISHED, () => {
            this.m_skin.getComponent(cc.Animation).play('jump');
        })
        
    };
    Tick(): void{

    };
    OnExit(): void{
        this.m_skin.getComponent(cc.Animation).play('jump-down');
    };
}

@ccclass
export default class Player extends cc.Component {


    body: cc.RigidBody = null;
    jumpSpeed = 200;
    maxSpeed = 100;
    acceleration = 1500;
    drag = 600;

    m_skin:cc.Node = null;

    speed = {x:0,y:0}

    private m_sm = new StateMachine();
    private m_idle: Idle;
    private m_run: Run;
    private m_attack: Attack;
    private m_jump: Jump;

    isAttack = false;
    // LIFE-CYCLE CALLBACKS:

    onLoad () {
        this.m_skin = this.node.getChildByName('skin');
        this.body = this.getComponent(cc.RigidBody);
        

        this.m_idle = new Idle(this.node);
        this.m_run = new Run(this.node);
        this.m_attack = new Attack(this.node);
        this.m_jump = new Jump(this.node);

        this.m_sm.AddTransition(this.m_idle, this.m_run,():boolean=>{
            return this.speed.x != 0;
        });

        this.m_sm.AddTransition(this.m_run, this.m_idle,():boolean=>{
            return this.speed.x == 0;
        });

        this.m_sm.AddTransition(this.m_idle, this.m_jump,():boolean=>{
            return this.speed.y != 0;
        });

        this.m_sm.AddTransition(this.m_run, this.m_jump,():boolean=>{
            return this.speed.y != 0;
        });

        this.m_sm.AddTransition(this.m_jump, this.m_idle,():boolean=>{
            return this.speed.y == 0;
        });

        // 添加攻击状态转换规则
        this.m_sm.AddTransition(this.m_idle, this.m_attack, ():boolean => {
            return this.isAttack;
        });
        this.m_sm.AddTransition(this.m_run, this.m_attack, ():boolean => {
            return this.isAttack;
        });
        this.m_sm.AddTransition(this.m_attack, this.m_idle, ():boolean => {
            return !this.isAttack;
        });



        // 初始为站立状态
        this.m_sm.SetState(this.m_idle);
    }

    start () {

    }

    faceLogic(){
        this.node.scaleX = this.speed.x >= 0 ? 1 : -1;
    }

    update (dt) {
        
        var speed = this.body.linearVelocity;
        if(speed.x != 0) {
            var d = this.drag * dt;
            if(Math.abs(speed.x) <= d) {
                speed.x = 0;
                // this.anim.play('idle');
            } else {
                speed.x -= speed.x > 0 ? d : -d;
            }
        }
        if (Input.axis.x) {
            this.faceLogic();
        }
        if (Input.getKey(KeyCode.A)) {
            speed.x -= this.acceleration * dt;
            if(speed.x < -this.maxSpeed) {
                speed.x = -this.maxSpeed;
            }
        }else if (Input.getKey(KeyCode.D)) {
            speed.x += this.acceleration * dt;
            if(speed.x > this.maxSpeed) {
                speed.x = this.maxSpeed;
            }
        }

        if (Input.getKey(KeyCode.J)) {
            if(!this.isAttack && this.m_sm.GetCurrentState().Name !== 'Attack') {
                this.isAttack = true;
            }
        }



        if (Input.getKey(KeyCode.W) || Input.getKey(KeyCode.Space)) {
            speed.y = this.jumpSpeed;
        }

        this.speed = speed;
        this.body.linearVelocity = speed;

        this.m_sm.Tick();
    }
}
